home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / DECAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  12.8 KB  |  612 lines

  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <GL/glut.h>
  5.  
  6. /* Some <math.h> files do not define M_PI... */
  7. #ifndef M_PI
  8. #define M_PI 3.14159265358979323846
  9. #endif
  10.  
  11. GLUquadricObj    *quadric;
  12. GLfloat     black[] = {0, 0, 0, 1};
  13. GLfloat     white[] = {1, 1, 1, 1};
  14.  
  15.  
  16. int         winWidth, winHeight;
  17. GLfloat     *depthSave = NULL;
  18. GLubyte     *stencilSave = NULL;
  19. GLubyte     *colorSave = NULL;
  20.  
  21.  
  22. void resizeBuffers(void)
  23. {
  24.     colorSave = realloc(colorSave, winWidth * winHeight * 4 * sizeof(GLubyte));
  25.     depthSave = realloc(depthSave, winWidth * winHeight * 4 * sizeof(GLfloat));
  26.     stencilSave = (GLubyte *)depthSave;
  27. }
  28.  
  29.  
  30. void pushOrthoView(float left, float right, float bottom, float top,
  31.     float znear, float zfar)
  32. {
  33.     glPushMatrix();
  34.     glLoadIdentity();
  35.     glMatrixMode(GL_PROJECTION);
  36.     glPushMatrix();
  37.     glLoadIdentity();
  38.     glOrtho(left, right, bottom, top, znear, zfar);
  39. }
  40.  
  41.  
  42. void popView(void)
  43. {
  44.     glPopMatrix();
  45.     glMatrixMode(GL_MODELVIEW);
  46.     glPopMatrix();
  47. }
  48.  
  49.  
  50. void copyDepthToColor(GLenum whichColorBuffer)
  51. {
  52.     int        x, y;
  53.     GLfloat    max, min;
  54.     GLint    previousColorBuffer;
  55.  
  56.     glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT, GL_FLOAT,
  57.         depthSave);
  58.  
  59.     /* I'm sure this could be done much better with OpenGL */
  60.     max = 0;
  61.     min = 1;
  62.     for(y = 0; y < winHeight; y++)
  63.     for(x = 0; x < winWidth; x++) {
  64.         if(depthSave[winWidth * y + x] < min)
  65.         min = depthSave[winWidth * y + x];
  66.         if(depthSave[winWidth * y + x] > max && depthSave[winWidth * y + x] < .999)
  67.         max = depthSave[winWidth * y + x];
  68.     }
  69.  
  70.     for(y = 0; y < winHeight; y++)
  71.     for(x = 0; x < winWidth; x++) {
  72.         if(depthSave[winWidth * y + x] <= max)
  73.         depthSave[winWidth * y + x] = 1 -  (depthSave[winWidth * y + x] - min) / (max - min);
  74.         else
  75.         depthSave[winWidth * y + x] = 0;
  76.     }
  77.  
  78.     pushOrthoView(0, 1, 0, 1, 0, 1);
  79.     glRasterPos3f(0, 0, -.5);
  80.     glDisable(GL_DEPTH_TEST);
  81.     glDisable(GL_STENCIL_TEST);
  82.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  83.     glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
  84.     glDrawBuffer(whichColorBuffer);
  85.     glDrawPixels(winWidth, winHeight, GL_LUMINANCE , GL_FLOAT, depthSave);
  86.     glDrawBuffer(previousColorBuffer);
  87.     glEnable(GL_DEPTH_TEST);
  88.     popView();
  89. }
  90.  
  91.  
  92. unsigned char colors[][3] =
  93. {
  94.     {255, 0, 0},    /* red */
  95.     {255, 218, 0},    /* yellow */
  96.     {72, 255, 0},    /* yellowish green */
  97.     {0, 255, 145},    /* bluish cyan */
  98.     {0, 145, 255},    /* cyanish blue */
  99.     {72, 0, 255},    /* purplish blue */
  100.     {255, 0, 218},    /* reddish purple */
  101. };
  102.  
  103.  
  104. void copyStencilToColor(GLenum whichColorBuffer)
  105. {
  106.     int        x, y;
  107.     GLint    previousColorBuffer;
  108.  
  109.     glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
  110.         stencilSave);
  111.  
  112.     /* I'm sure this could be done much better with OpenGL */
  113.     for(y = 0; y < winHeight; y++)
  114.     for(x = 0; x < winWidth; x++) {
  115.         int stencilValue;
  116.         
  117.         stencilValue = stencilSave[winWidth * y + x];
  118.  
  119.         colorSave[(winWidth * y + x) * 3 + 0] = colors[stencilValue % 7][0];
  120.         colorSave[(winWidth * y + x) * 3 + 1] = colors[stencilValue % 7][1];
  121.         colorSave[(winWidth * y + x) * 3 + 2] = colors[stencilValue % 7][2];
  122.     }
  123.  
  124.     pushOrthoView(0, 1, 0, 1, 0, 1);
  125.     glRasterPos3f(0, 0, -.5);
  126.     glDisable(GL_DEPTH_TEST);
  127.     glDisable(GL_STENCIL_TEST);
  128.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  129.     glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
  130.     glDrawBuffer(whichColorBuffer);
  131.     glDrawPixels(winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, colorSave);
  132.     glDrawBuffer(previousColorBuffer);
  133.     glEnable(GL_DEPTH_TEST);
  134.     popView();
  135. }
  136.  
  137.  
  138. int useStencil = 0;
  139. int stage = 6;
  140. typedef enum {COLOR, DEPTH, STENCIL} DataChoice;
  141. DataChoice dataChoice = COLOR;
  142.  
  143. void init(void)
  144. {
  145.     glEnable(GL_DEPTH_TEST);
  146.     glEnable(GL_CULL_FACE);
  147.     glCullFace(GL_BACK);
  148.  
  149.     quadric = gluNewQuadric();
  150.  
  151.     glMatrixMode(GL_PROJECTION);
  152.     glFrustum(-.33, .33, -.33, .33, .5, 40);
  153.  
  154.     glMatrixMode(GL_MODELVIEW);
  155.     gluLookAt(-4, 10, 6, 0, 0, 0, 0, 1, 0);
  156.  
  157.     glEnable(GL_LIGHTING);
  158.     glEnable(GL_LIGHT0);
  159.  
  160.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  161.  
  162.     glEnable(GL_NORMALIZE);
  163.  
  164.     /*
  165.      * only need this to clear stencil and only need to clear stencil
  166.      * when you're looking at it; the algorithm works without it.
  167.      */
  168.     glClearStencil(5);
  169. }
  170.  
  171.  
  172. void setupLight(void)
  173. {
  174.     static GLfloat     lightpos[] = {0, 1, 0, 0};
  175.  
  176.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  177. }
  178.  
  179.  
  180. void setupNormalDrawingState(void)
  181. {
  182.     glDisable(GL_STENCIL_TEST);
  183.     glEnable(GL_DEPTH_TEST);
  184.     glDepthMask(1);
  185. }
  186.  
  187. void setupBasePolygonState(int maxDecal)
  188. {
  189.     glEnable(GL_DEPTH_TEST);
  190.     if(useStencil) {
  191.     glEnable(GL_STENCIL_TEST);
  192.     glStencilFunc(GL_ALWAYS, maxDecal + 1, 0xff);
  193.     glStencilOp(GL_KEEP, GL_REPLACE, GL_ZERO);
  194.     }
  195. }
  196.  
  197.  
  198. void setupDecalState(int decalNum)
  199. {
  200.     if(useStencil) {
  201.     glDisable(GL_DEPTH_TEST);
  202.     glDepthMask(0);
  203.     glEnable(GL_STENCIL_TEST);
  204.     glStencilFunc(GL_GREATER, decalNum, 0xff);
  205.     glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  206.     }
  207. }
  208.  
  209.  
  210. void drawAirplane(void)
  211. {
  212.     GLfloat airplaneColor[4] = {.75, .75, .75, 1};
  213.  
  214.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, airplaneColor);
  215.  
  216.     glDisable(GL_CULL_FACE);
  217.  
  218.     glPushMatrix();
  219.     glTranslatef(0, 0, -2.5);
  220.  
  221.     gluCylinder(quadric, .5, .5, 5, 10, 10);
  222.  
  223.     glPushMatrix();
  224.     glTranslatef(0, 0, 5);
  225.     gluCylinder(quadric, .5, 0, 1, 10, 10);
  226.     glPopMatrix();
  227.  
  228.     glPushMatrix();
  229.     glTranslatef(0, 0, 3);
  230.     glScalef(3, .1, 1);
  231.     gluSphere(quadric, 1, 10, 10);
  232.     glPopMatrix();
  233.  
  234.     glPushMatrix();
  235.     glTranslatef(0, 0, .5);
  236.     glScalef(2, .1, .5);
  237.     gluSphere(quadric, 1, 10, 10);
  238.     glPopMatrix();
  239.  
  240.     glEnable(GL_CULL_FACE);
  241.  
  242.     glBegin(GL_TRIANGLES);
  243.     glNormal3f(1, 0, 0);
  244.     glVertex3f(0, 1.5, 0);
  245.     glVertex3f(0, .5, 1);
  246.     glVertex3f(0, .5, 0);
  247.     glNormal3f(-1, 0, 0);
  248.     glVertex3f(0, 1.5, 0);
  249.     glVertex3f(0, .5, 0);
  250.     glVertex3f(0, .5, 1);
  251.     glEnd();
  252.  
  253.     glDisable(GL_CULL_FACE);
  254.  
  255.     glRotatef(180, 0, 1, 0);
  256.     gluDisk(quadric, 0, .5, 10, 10);
  257.  
  258.     glPopMatrix();
  259.  
  260.     glEnable(GL_CULL_FACE);
  261. }
  262.  
  263.  
  264. void drawGround(void)
  265. {
  266.     GLfloat groundColor[4] = {.647, .165, .165, 1};
  267.  
  268.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, groundColor);
  269.  
  270.     glBegin(GL_QUADS);
  271.     glNormal3i(0, 1, 0);
  272.     glVertex3f(10, 0, 10);
  273.     glVertex3f(10, 0, -10);
  274.     glVertex3f(-10, 0, -10);
  275.     glVertex3f(-10, 0, 10);
  276.     glEnd();
  277. }
  278.  
  279.  
  280. void drawAsphalt(void)
  281. {
  282.     GLfloat asphaltColor[4] = {.25, .25, .25, 1};
  283.  
  284.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, asphaltColor);
  285.  
  286.     glBegin(GL_QUADS);
  287.     glNormal3i(0, 1, 0);
  288.     glVertex3f(5, 0, 9.5);
  289.     glVertex3f(5, 0, -9.5);
  290.     glVertex3f(-5, 0, -9.5);
  291.     glVertex3f(-5, 0, 9.5);
  292.     glEnd();
  293. }
  294.  
  295.  
  296. int    numStripes = 5;
  297. float    stripeGap = .66;
  298.  
  299.  
  300. void drawStripes(void)
  301. {
  302.     GLfloat    stripeColor[4] = {1, 1, 0, 1};
  303.     int        i;
  304.     float    stripeLength;
  305.  
  306.     stripeLength = (16 - stripeGap * (numStripes - 1)) / numStripes;
  307.  
  308.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, stripeColor);
  309.  
  310.     glBegin(GL_QUADS);
  311.  
  312.     glNormal3i(0, 1, 0);
  313.  
  314.     glVertex3f(4.5, 0, 8.5);
  315.     glVertex3f(4.5, 0, -8.5);
  316.     glVertex3f(3.5, 0, -8.5);
  317.     glVertex3f(3.5, 0, 8.5);
  318.  
  319.     glVertex3f(-3.5, 0, 8.5);
  320.     glVertex3f(-3.5, 0, -8.5);
  321.     glVertex3f(-4.5, 0, -8.5);
  322.     glVertex3f(-4.5, 0, 8.5);
  323.  
  324.     for(i = 0; i < numStripes; i++) {
  325.         glVertex3f(.5, 0, 8 - i * (stripeLength + stripeGap));
  326.         glVertex3f(.5, 0, 8 - i * (stripeLength + stripeGap) - stripeLength);
  327.         glVertex3f(-.5, 0, 8 - i * (stripeLength + stripeGap) - stripeLength);
  328.         glVertex3f(-.5, 0, 8 - i * (stripeLength + stripeGap));
  329.     }
  330.     glEnd();
  331. }
  332.  
  333.  
  334. void redraw(void)
  335. {
  336.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  337.     
  338.     /* Only need this if you care to look at the stencil buffer */
  339.     if(dataChoice == STENCIL)
  340.     glClear(GL_STENCIL_BUFFER_BIT);
  341.  
  342.     glPushMatrix();
  343.     glScalef(.5, .5, .5);
  344.  
  345.     if(stage == 1)
  346.        goto doneWithFrame;
  347.  
  348.     setupLight();
  349.  
  350.     setupNormalDrawingState();
  351.     glPushMatrix();
  352.     glTranslatef(0, 1, 4);
  353.     glRotatef(135, 0, 1, 0);
  354.     drawAirplane();
  355.     glPopMatrix();
  356.  
  357.     if(stage == 2)
  358.        goto doneWithFrame;
  359.  
  360.     setupBasePolygonState(3);    /* 2 decals */
  361.     drawGround();
  362.  
  363.     if(stage == 3)
  364.        goto doneWithFrame;
  365.  
  366.     setupDecalState(1);        /* decal # 1 = the runway asphalt */
  367.     drawAsphalt();
  368.  
  369.     if(stage == 4)
  370.        goto doneWithFrame;
  371.  
  372.     setupDecalState(2);        /* decal # 2 = yellow paint on the runway */
  373.     drawStripes();
  374.  
  375.     if(stage == 5)
  376.        goto doneWithFrame;
  377.  
  378.     setupDecalState(3);        /* decal # 3 = the plane's shadow */
  379.     glDisable(GL_LIGHTING);
  380.     glEnable(GL_BLEND);
  381.     glPushMatrix();
  382.     glColor4f(0, 0, 0, .5);
  383.     glTranslatef(0, 0, 4);
  384.     glRotatef(135, 0, 1, 0);
  385.     glScalef(1, 0, 1);
  386.     drawAirplane();
  387.     glPopMatrix();
  388.     glDisable(GL_BLEND);
  389.     glEnable(GL_LIGHTING);
  390.  
  391. doneWithFrame:
  392.  
  393.     setupNormalDrawingState();
  394.  
  395.     glPopMatrix();
  396.  
  397.     switch(dataChoice) {
  398.         case COLOR:
  399.         break; /* color already in back buffer */
  400.  
  401.     case STENCIL:
  402.         copyStencilToColor(GL_BACK);
  403.         break;
  404.  
  405.     case DEPTH:
  406.         copyDepthToColor(GL_BACK);
  407.         break;
  408.     }
  409.  
  410.     glutSwapBuffers();
  411. }
  412.  
  413.  
  414. void reshape(int width, int height)
  415. {
  416.     glViewport(0, 0, width, height);
  417.     winWidth = width;
  418.     winHeight = height;
  419.     resizeBuffers();
  420.     glutPostRedisplay();
  421. }
  422.  
  423.  
  424. static int ox, oy;
  425. static int mode;
  426.  
  427.  
  428. /* ARGSUSED */
  429. void button(int b, int state, int x, int y)
  430. {
  431.     ox = x;
  432.     oy = y;
  433.     mode = b;
  434. }
  435.  
  436.  
  437. void motion(int x, int y)
  438. {
  439.     static float ang = 0;
  440.     static float height = 10;
  441.     float eyex, eyez;
  442.  
  443.     if(mode == GLUT_LEFT_BUTTON)
  444.     {
  445.         ang += (x - ox) / 512.0 * M_PI;
  446.         height += (y - oy) / 512.0 * 10;
  447.     eyex = cos(ang) * 7;
  448.     eyez = sin(ang) * 7;
  449.     glLoadIdentity();
  450.     gluLookAt(eyex, height, eyez, 0, 0, 0, 0, 1, 0);
  451.         glutPostRedisplay();
  452.     ox = x;
  453.     oy = y;
  454.     }
  455. }
  456.  
  457.  
  458. void changeData(int data)
  459. {
  460.     char *s;
  461.  
  462.     dataChoice = data;
  463.     glutPostRedisplay();
  464.  
  465.     switch(data) {
  466.         case COLOR:
  467.         s = "color";
  468.         break;
  469.  
  470.         case STENCIL:
  471.         s = "stencil";
  472.         break;
  473.  
  474.         case DEPTH:
  475.         s = "depth";
  476.         break;
  477.     }
  478.     printf("Now displaying %s data\n", s);
  479. }
  480.  
  481.  
  482. void changeStage(int data)
  483. {
  484.     char *s;
  485.  
  486.     stage = data;
  487.     glutPostRedisplay();
  488.     switch(data) {
  489.         case 1:
  490.         s = "clearing";
  491.         break;
  492.  
  493.         case 2:
  494.         s = "drawing airplane";
  495.         break;
  496.  
  497.         case 3:
  498.         s = "drawing ground";
  499.         break;
  500.  
  501.         case 4:
  502.         s = "drawing asphalt";
  503.         break;
  504.  
  505.         case 5:
  506.         s = "drawing paint";
  507.         break;
  508.  
  509.         case 6:
  510.         s = "drawing shadow";
  511.         break;
  512.     }
  513.     printf("Now displaying frame after %s\n", s);
  514. }
  515.  
  516.  
  517. int mainMenu;
  518.  
  519. void stencilDecalEnable(int enabled)
  520. {
  521.     glutSetMenu(mainMenu);
  522.     if(enabled){
  523.     glutChangeToMenuEntry(1, "Turn off stencil decal", 0);
  524.     printf("Stencil decaling turned on\n");
  525.     glutPostRedisplay();
  526.     } else {
  527.     glutChangeToMenuEntry(1, "Turn on stencil decal", 1);
  528.     printf("Stencil decaling turned off\n");
  529.     glutPostRedisplay();
  530.     }
  531.     useStencil = enabled;
  532. }
  533.  
  534.  
  535. /*
  536.  * Basically shortcuts for menu items
  537.  */
  538. /* ARGSUSED1 */
  539. void keyboard(unsigned char key, int x, int y)
  540. {
  541.     switch(key) {
  542.         case '1':
  543.         case '2':
  544.         case '3':
  545.         case '4':
  546.         case '5':
  547.         case '6':
  548.         changeStage(key - '0');
  549.         break;
  550.  
  551.     case 's': case 'S':
  552.         stencilDecalEnable(! useStencil);
  553.         break;
  554.  
  555.     case 'q': case 'Q': case '\033':
  556.         exit(0);
  557.         break;
  558.  
  559.     default:
  560.         fprintf(stderr, "Push right mouse button for menu\n");
  561.         break;
  562.     }
  563. }
  564.  
  565.  
  566. int main(int argc, char **argv)
  567. {
  568.     int bufferMenu;
  569.     int finishMenu;
  570.     int stenSize;
  571.  
  572.     glutInitWindowSize(winWidth = 512, winHeight = 512);
  573.     glutInit(&argc, argv);
  574.     glutInitDisplayString("samples stencil>=3 rgb double depth");
  575.     /* glutInitDisplayMode(GLUT_DOUBLE|GLUT_STENCIL|GLUT_DEPTH|GLUT_ALPHA); */
  576.     (void)glutCreateWindow("decaling using stencil");
  577.     glutDisplayFunc(redraw);
  578.     glutKeyboardFunc(keyboard);
  579.     glutMotionFunc(motion);
  580.     glutMouseFunc(button);
  581.     glutReshapeFunc(reshape);
  582.  
  583.     resizeBuffers();
  584.     glGetIntegerv(GL_STENCIL_BITS, &stenSize);
  585.     fprintf(stderr, "(%d bits of stencil available in this visual)\n", stenSize);
  586.  
  587.     fprintf(stderr, "Hit 'h' for help message\n");
  588.  
  589.     finishMenu = glutCreateMenu(changeStage);
  590.     glutAddMenuEntry("Clearing screen", 1);
  591.     glutAddMenuEntry("Drawing airplane", 2);
  592.     glutAddMenuEntry("Drawing ground ", 3);
  593.     glutAddMenuEntry("Drawing asphalt", 4);
  594.     glutAddMenuEntry("Drawing paint", 5);
  595.     glutAddMenuEntry("Drawing shadow", 6);
  596.  
  597.     bufferMenu = glutCreateMenu(changeData);
  598.     glutAddMenuEntry("Color data", COLOR);
  599.     glutAddMenuEntry("Stencil data", STENCIL);
  600.     glutAddMenuEntry("Depth data", DEPTH);
  601.  
  602.     mainMenu = glutCreateMenu(stencilDecalEnable);
  603.     glutAddMenuEntry("Turn on stencil decal", 1);
  604.     glutAddSubMenu("Visible buffer", bufferMenu);
  605.     glutAddSubMenu("Finish frame after...", finishMenu);
  606.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  607.     init();
  608.     glutMainLoop();
  609.  
  610.     return 0;
  611. }
  612.